package com.mixed;

//import org.apache.commons.codec.binary.Base64;
import java.io.*;
import java.security.*;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.*;
import java.security.interfaces.*;
import java.security.spec.*;

public class RSA {

    public static boolean genKeyPair() {
        // KeyPairGenerator类用于生成公钥和私钥对，基于RSA算法生成对象
        KeyPairGenerator keyPairGen = null;
        try {
            keyPairGen = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        // 初始化密钥对生成器
        keyPairGen.initialize(2048,new SecureRandom());
        // 生成一个密钥对，保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        // 得到私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        // 得到公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        try {

            // 得到公钥字符串,base64编码
            String publicKeyString = (new BASE64Encoder()).encode(publicKey.getEncoded());
            String privateKeyString = (new BASE64Encoder()).encode(privateKey.getEncoded());
            // 将密钥对写入到文件
            FileWriter pubfw = new FileWriter("public_key.dat");
            FileWriter prifw = new FileWriter("private_key.dat");
            BufferedWriter pubbw = new BufferedWriter(pubfw);
            BufferedWriter pribw = new BufferedWriter(prifw);
            pubbw.write(publicKeyString);
            pribw.write(privateKeyString);
            pubbw.flush();
            pubbw.close();
            pubfw.close();
            pribw.flush();
            pribw.close();
            prifw.close();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public static String encrypt(String reqData, String publicKey) throws Exception{
        byte[] buffer = (new BASE64Decoder()).decodeBuffer(publicKey);//publicKey 为base64编码的字符串形式，要将其解码
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
        RSAPublicKey pck = (RSAPublicKey) keyFactory.generatePublic(keySpec);

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pck);
        byte[] output = cipher.doFinal(reqData.getBytes());
        return (new BASE64Encoder()).encode(output);//将得到的的密文字节数组以base64编码字符串输出
    }

    /*
      **此方法专用于在服务器中加密DES密钥。DES密钥已被转为base64编码，因此读取明文（即DES密钥）的方式有效
    */
    public static void DESKeyEncrypt(String plainpath, String keypath, String cipherpath) throws Exception {
        String key = loadKeyByFile(keypath);
        BufferedReader br = new BufferedReader(new FileReader(plainpath));
        String readLine = null;
        StringBuilder sb = new StringBuilder();
        while ((readLine = br.readLine()) != null) {
            sb.append(readLine);
        }
        br.close();
        BufferedWriter wt = new BufferedWriter(new FileWriter(cipherpath));
        String cipher = encrypt(sb.toString(), key);
        wt.write(cipher);
        wt.flush();
        wt.close();
    }

    //密文为base64编码的字符串
    public static void DESKeyDecrypt(String cipherpath, String keypath, String plainpath) throws Exception {
        String key = loadKeyByFile(keypath);
        BufferedReader br = new BufferedReader(new FileReader(cipherpath));
        String readLine = null;
        StringBuilder sb = new StringBuilder();
        while ((readLine = br.readLine()) != null) {
            sb.append(readLine);
        }
        br.close();
        BufferedWriter wt = new BufferedWriter(new FileWriter(plainpath));
        String plain = decrypt(sb.toString(), key);
        wt.write(plain);
        wt.flush();
        wt.close();
    }

    public static String loadKeyByFile(String path) throws Exception {
        try {
            BufferedReader br = new BufferedReader(new FileReader(path));
            String readLine = null;
            StringBuilder sb = new StringBuilder();
            while ((readLine = br.readLine()) != null) {
                sb.append(readLine);
            }
            br.close();
            return sb.toString();
        } catch (IOException e) {
            throw new Exception("秘钥数据流读取错误");
        } catch (NullPointerException e) {
            throw new Exception("秘钥输入流为空");
        }
    }

    public static String decrypt(String signStr, String privateKey) throws Exception {
        BASE64Decoder base64Decoder = new BASE64Decoder();
        RSAPrivateKey prk = null;
        byte[] buffer = base64Decoder.decodeBuffer(privateKey);//密钥为base64的字符串，需要解码！
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        prk = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, prk);
        byte[] content = cipher.doFinal(base64Decoder.decodeBuffer(signStr));//密文为base64的字符串，需要解码
        return new String(content, "UTF-8");
    }

    //此方法为了方便服务器MixedEncrypt.java中的操作。DESKey 为base64编码的DES密钥字符串。
    static void FastEncrypt(String DESKey, String RSAkey, String encryptDESKeyPath) throws Exception {
        //String RSAkey = loadKeyByFile(RSAkeypath);
        BufferedWriter wt = new BufferedWriter(new FileWriter(encryptDESKeyPath));
        String cipher = encrypt(DESKey, RSAkey);
        wt.write(cipher);
        wt.flush();
        wt.close();
    }
}